home *** CD-ROM | disk | FTP | other *** search
/ Explorer - Mosaic & Web / Explorer - Mosaic & Web.iso / helpers / ghostvew / src / gvceps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-01  |  29.2 KB  |  1,123 lines

  1. /* Copyright (C) 1993, 1994, Russell Lang.  All rights reserved.
  2.   
  3.   This file is part of GSview.
  4.   
  5.   This program is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the GSview Free Public Licence 
  9.   (the "Licence") for full details.
  10.   
  11.   Every copy of GSview must include a copy of the Licence, normally in a 
  12.   plain ASCII text file named LICENCE.  The Licence grants you the right 
  13.   to copy, modify and redistribute GSview, but only under certain conditions 
  14.   described in the Licence.  Among other things, the Licence requires that 
  15.   the copyright notice and this notice be preserved on all copies.
  16. */
  17.  
  18. /* gvceps.c */
  19. /* EPS file manipulation module of PM and Windows GSview */
  20.  
  21. #ifdef EPSTOOL
  22. #include "epstool.h"
  23. #else    /* GSview */
  24. #ifdef _Windows
  25. #include "gvwin.h"
  26. #else
  27. #include "gvpm.h"
  28. #endif
  29. #include "gvceps.h"
  30. #endif
  31.  
  32. PSBBOX bbox;
  33.  
  34. #ifndef EPSTOOL
  35. /* At present only allows bounding box to be specified */
  36. void
  37. ps_to_eps(void)
  38. {
  39. char output[MAXSTR];
  40. FILE *f;
  41. char *buffer;
  42. UINT count;
  43. FILE *infile;
  44. time_t t;
  45. char *now;
  46. char text[PSLINELENGTH];
  47. char *comment;
  48. long here;
  49.  
  50.     load_string(IDS_EPSREAD, output, sizeof(output));
  51.     if (message_box(output, MB_YESNO | MB_ICONQUESTION)
  52.         != IDYES) {
  53.         load_string(IDS_TOPICPSTOEPS, szHelpTopic, sizeof(szHelpTopic));
  54.         get_help();
  55.         return;
  56.     }
  57.  
  58.     if (!(display.page || display.sync)) {
  59.         gserror(IDS_EPSNOBBOX, NULL, MB_ICONEXCLAMATION, SOUND_ERROR);
  60.         return;
  61.     }
  62.  
  63.     if ((doc != (PSDOC *)NULL) && (doc->numpages > 1)) {
  64.         gserror(IDS_EPSONEPAGE, NULL, MB_ICONEXCLAMATION, SOUND_ERROR);
  65.         return;
  66.     }
  67.     if (doc == (PSDOC *)NULL) {
  68.         char mess[MAXSTR];
  69.         load_string(IDS_EPSQPAGES, mess, sizeof(mess));
  70.         if (message_box(mess, MB_YESNO | MB_ICONQUESTION) != IDYES)
  71.         return;
  72.     }
  73.  
  74.     if (!get_bbox()) {
  75.         play_sound(SOUND_ERROR);
  76.         return;
  77.     }
  78.  
  79.     output[0] = '\0';
  80.     if (!get_filename(output, TRUE, FILTER_PS, 0, IDS_TOPICPSTOEPS))
  81.         return;
  82.  
  83.     if ((f = fopen(output, "wb")) == (FILE *)NULL) {
  84.         play_sound(SOUND_ERROR);
  85.         return;
  86.     }
  87.  
  88.     if (doc == (PSDOC *)NULL) {
  89.         load_string(IDS_WAITWRITE, szWait, sizeof(szWait));
  90.         info_wait(TRUE);
  91.         fputs("%!PS-Adobe-3.0 EPSF-3.0\r\n",f);
  92.         /* if this is not a single page document then gsview has just lied */
  93.         fprintf(f, "%%%%BoundingBox: %u %u %u %u\r\n",
  94.         bbox.llx,bbox.lly,bbox.urx,bbox.ury);
  95.         fprintf(f,"%%%%Title: %s\r\n",psfile.name);
  96.         fprintf(f,"%%%%Creator: %s from %s\r\n",szAppName,psfile.name);
  97.         t = time(NULL);
  98.         now = ctime(&t);
  99.         now[strlen(now)-1] = '\0';    /* remove trailing \n */
  100.         fprintf(f,"%%%%CreationDate: %s\r\n",now);
  101.         fputs("%%Pages: 1\r\n",f);
  102.         fputs("%%EndComments\r\n",f);
  103.  
  104.         fputs("%%Page: 1 1\r\n",f);
  105.         fprintf(f,"%%BeginDocument: %s\r\n",psfile.name);
  106.  
  107.         /* create buffer for PS file copy */
  108.         buffer = malloc(COPY_BUF_SIZE);
  109.         if (buffer == (char *)NULL) {
  110.             play_sound(SOUND_ERROR);
  111.             fclose(f);
  112.         unlink(output);
  113.             return;
  114.         }
  115.  
  116.         infile = fopen(psfile.name, "rb");
  117.         if (infile == (FILE *)NULL) {
  118.             play_sound(SOUND_ERROR);
  119.             fclose(f);
  120.         unlink(output);
  121.             return;
  122.         }
  123.  
  124.             while ( (count = fread(buffer, 1, COPY_BUF_SIZE, infile)) != 0 ) {
  125.             fwrite(buffer, 1, count, f);
  126.         }
  127.         free(buffer);
  128.         fclose(infile);
  129.  
  130.         fputs("%%EndDocument\r\n",f);
  131.         fputs("%%Trailer\r\n",f);
  132.         fclose(f);
  133.         info_wait(FALSE);
  134.     }
  135.     else {
  136.         /* document already has DSC comments */
  137.         load_string(IDS_WAITWRITE, szWait, sizeof(szWait));
  138.         info_wait(TRUE);
  139.         dfreopen();
  140.         fseek(psfile.file, doc->begincomments, SEEK_SET);
  141.         fgets(text, PSLINELENGTH, psfile.file);
  142.         if (doc->epsf)
  143.             fputs(text,f);
  144.         else
  145.             fputs("%!PS-Adobe-3.0 EPSF-3.0\r\n",f);
  146.         if (doc->bbox.valid) {
  147.             if ( (comment = dsc_copy(psfile.file, f, -1,
  148.                doc->endcomments, "%%BoundingBox:")) != (char *)NULL ) {
  149.             free(comment);
  150.             }
  151.         }
  152.         fprintf(f, "%%%%BoundingBox: %d %d %d %d\r\n",
  153.         bbox.llx, bbox.lly, bbox.urx, bbox.ury);
  154.         here = ftell(psfile.file);
  155.         dsc_copy(psfile.file, f, here, doc->endtrailer, NULL);
  156.         dfclose();
  157.         fclose(f);
  158.         info_wait(FALSE);
  159.     }
  160. }
  161. #endif
  162.  
  163. typedef struct tagWINRECT {
  164.     WORD    left;
  165.     WORD    top;
  166.     WORD    right;
  167.     WORD    bottom;
  168. } WINRECT;
  169.  
  170. typedef struct {
  171.     DWORD    key;
  172.     WORD     hmf;
  173.     WINRECT     bbox;
  174.     WORD    inch;
  175.     DWORD    reserved;
  176.     WORD    checksum;
  177. } METAFILEHEADER;
  178.  
  179.  
  180. /* extract EPS or TIFF or WMF file from DOS EPS file */
  181. void 
  182. extract_doseps(int command)
  183. {
  184. unsigned long pos;
  185. unsigned long len;
  186. unsigned int count;
  187. char *buffer;
  188. FILE* epsfile;
  189. BOOL is_meta = TRUE;
  190. char outname[MAXSTR];
  191. FILE *outfile;
  192. unsigned int filter;
  193.     if ((doc == (PSDOC *)NULL) || (doc->doseps == (DOSEPS *)NULL)) {
  194.         gserror(IDS_NOPREVIEW, NULL, MB_ICONEXCLAMATION, SOUND_ERROR);
  195.         return;
  196.     }
  197.     epsfile = fopen(psfile.name,"rb");
  198.     pos = doc->doseps->ps_begin;
  199.     len = doc->doseps->ps_length;
  200.     if (command == IDM_EXTRACTPRE) {
  201.         pos = doc->doseps->mf_begin;
  202.         len = doc->doseps->mf_length;
  203.         if (pos == 0L) {
  204.             pos = doc->doseps->tiff_begin;
  205.             len = doc->doseps->tiff_length;
  206.             is_meta = FALSE;
  207.         }
  208.     }
  209.     if (pos == 0L) {
  210.         fclose(epsfile);
  211.         gserror(IDS_NOPREVIEW, NULL, MB_ICONEXCLAMATION, SOUND_ERROR);
  212.         return;
  213.     }
  214.     fseek(epsfile, pos, SEEK_SET);    /* seek to section to extract */
  215.  
  216.  
  217. #ifdef EPSTOOL
  218.     /* assume outname already exists */
  219.     strcpy(outname, oname);
  220.     if (*outname!='\0')
  221.         outfile = fopen(outname,"wb");
  222.     else
  223.         outfile = stdout;
  224. #else
  225.     /* create postscript or preview file */
  226.     outname[0] = '\0';
  227.     if (command == IDM_EXTRACTPRE) {
  228.         if (is_meta)
  229.             filter = FILTER_WMF;
  230.         else
  231.             filter = FILTER_TIFF;
  232.     }
  233.     else
  234.         filter = FILTER_PS;
  235.     if (!get_filename(outname, TRUE, filter, 0, IDS_TOPICEDIT)) {
  236.         fclose(epsfile);
  237.         return;
  238.     }
  239.     outfile = fopen(outname, "wb");
  240. #endif
  241.     if (outfile == (FILE *)NULL) {
  242.         play_sound(SOUND_ERROR);
  243.         fclose(epsfile);
  244.         return;
  245.     }
  246.     
  247.     /* create buffer for file copy */
  248.     buffer = malloc(COPY_BUF_SIZE);
  249.     if (buffer == (char *)NULL) {
  250.         play_sound(SOUND_ERROR);
  251.         fclose(epsfile);
  252.         if (*outname!='\0')
  253.             fclose(outfile);
  254.         return;
  255.     }
  256.  
  257.     if ((command == IDM_EXTRACTPRE) && is_meta) {
  258.         /* write placeable Windows Metafile header */
  259.         METAFILEHEADER mfh;
  260.         int i;
  261.         unsigned short *pw;
  262.         mfh.key = reorder_dword(0x9ac6cdd7L);
  263.         mfh.hmf = 0;
  264.         mfh.bbox.left = 0;
  265.         mfh.bbox.right = reorder_word((WORD)(doc->bbox.urx - doc->bbox.llx));
  266.         mfh.bbox.top = 0;
  267.         mfh.bbox.bottom = reorder_word((WORD)(doc->bbox.ury - doc->bbox.lly));
  268.         mfh.inch = reorder_word(72);    /* PostScript points */
  269.         mfh.reserved = 0L;
  270.         mfh.checksum =  0;
  271.         pw = (WORD *)&mfh;
  272.         for (i=0; i<10; i++) {
  273.             mfh.checksum ^= *pw++;
  274.         }
  275.         fwrite(&mfh, sizeof(mfh), 1, outfile);
  276.     }
  277.  
  278.         while ( (count = (unsigned int)min(len,COPY_BUF_SIZE)) != 0 ) {
  279.         count = fread(buffer, 1, count, epsfile);
  280.         fwrite(buffer, 1, count, outfile);
  281.         len -= count;
  282.     }
  283.     free(buffer);
  284.     fclose(epsfile);
  285.     if (*outname!='\0')
  286.         fclose(outfile);
  287. }
  288.  
  289.  
  290. /* These routines deal with a PBM bitmap under Unix */
  291. /* and a BMP under OS/2 or MS-DOS */
  292.  
  293. /* a structure for holding details of a bitmap used for constructing */
  294. /* an EPS preview */
  295. typedef struct tagPREBMAP {
  296.     int  width;
  297.     int  height;
  298.     int  depth;
  299.     int  bytewidth;    /* length of each scan line in bytes */
  300.     BYTE GVHUGE* bits;
  301.     BOOL topleft;
  302. } PREBMAP;
  303.  
  304. void scan_bbox(PREBMAP *pprebmap, PSBBOX *psbbox);
  305. void shift_preview(unsigned char *preview, int bwidth, int offset);
  306.  
  307.  
  308. char isblack[256];    /* each byte is non-zero if that colour is black */
  309.  
  310. BOOL
  311. iswhitespace(char c)
  312. {
  313.     return (c==' ' || c=='\t' || c=='\r' || c=='\n');
  314. }
  315.  
  316. /* this doesn't do a good job of scanning pbm format */
  317. /* instead it makes assumptions about the way Ghostscript writes pbm files */
  318. void
  319. scan_pbmplus(PREBMAP *ppbmap, LPBITMAP2 pbm)
  320. {
  321. char *pbitmap;
  322. char *p;
  323. int i;
  324.     pbitmap = (char *)pbm;
  325.     if (pbitmap[0] == 'P' && (pbitmap[1] == '4' || pbitmap[1] == '5')) {
  326.     /* pbmraw */
  327.     p = pbitmap+3;
  328.     while (*p!='\n')
  329.         p++;    /* skip comment line */
  330.     p++;
  331.     ppbmap->width = atoi(p);
  332.     while (isdigit(*p))
  333.         p++;
  334.     while (iswhitespace(*p))
  335.         p++;
  336.     ppbmap->height = atoi(p);
  337.     while (isdigit(*p))
  338.         p++;
  339.     if (pbitmap[1] == '4') {    /* pbmraw */
  340.         ppbmap->depth = 1;
  341.         isblack[0] = 0;
  342.         isblack[1] = 1;
  343.     }
  344.     else {                /* pgmraw */
  345.         while (iswhitespace(*p))
  346.             p++;
  347.         ppbmap->depth = atoi(p);
  348.         while (isdigit(*p))
  349.             p++;
  350.         for (i=0; i<ppbmap->depth; i++)
  351.         isblack[i] = (char)(i!=0);
  352.     }
  353.     ppbmap->bits = ((BYTE GVHUGE *)p) +1;
  354.         ppbmap->bytewidth = (( ppbmap->width * ppbmap->depth + 7) & ~7) >> 3;
  355.     ppbmap->topleft = TRUE;
  356.     }
  357.     else {
  358.     gserror(0, "Unknown bitmap format", MB_ICONEXCLAMATION, SOUND_ERROR);
  359.     }
  360. }
  361.  
  362. #ifdef UNIX
  363. void
  364. scan_dib(PREBMAP *ppbmap, LPBITMAP2 pbm)
  365. {
  366.     fprintf(stderr, "Can't handle BMP format under Unix");
  367. }
  368.  
  369. #else
  370. void scan_colors(PREBMAP *ppbmap, LPBITMAP2 pbm);
  371.  
  372. void
  373. scan_dib(PREBMAP *ppbmap, LPBITMAP2 pbm)
  374. {
  375.     if (pbm->biSize == sizeof(BITMAP1)) {
  376.     ppbmap->width = ((LPBITMAP1)pbm)->bcWidth;
  377.     ppbmap->height = ((LPBITMAP1)pbm)->bcHeight;
  378.     ppbmap->depth = ((LPBITMAP1)pbm)->bcBitCount;
  379.         ppbmap->bytewidth = (( ppbmap->width * ppbmap->depth + 31) & ~31) >> 3;
  380.     ppbmap->bits =  (((BYTE GVHUGE *)pbm) + pbm->biSize)
  381.             + dib_pal_colors(pbm) * sizeof(RGB3); 
  382.     ppbmap->topleft = FALSE;
  383.     }
  384.     else {
  385.     ppbmap->width = (int)pbm->biWidth;
  386.     ppbmap->height = (int)pbm->biHeight;
  387.     ppbmap->depth = pbm->biBitCount;
  388.         ppbmap->bytewidth = (int)(((pbm->biWidth * pbm->biBitCount + 31) & ~31) >> 3);
  389.     ppbmap->bits =  (((BYTE GVHUGE *)pbm) + pbm->biSize)
  390.             + dib_pal_colors(pbm) * sizeof(RGB4); 
  391.     ppbmap->topleft = FALSE;
  392.     }
  393.     scan_colors(ppbmap, pbm);
  394. }
  395.  
  396. /* return number of bytes per line, rounded up to multiple of 4 bytes */
  397. unsigned long
  398. dib_bytewidth(LPBITMAP2 pbm)
  399. {
  400. unsigned long l;
  401.     if (pbm->biSize == sizeof(BITMAP1)) {
  402.         l = ((( ((LPBITMAP1)pbm)->bcWidth * ((LPBITMAP1)pbm)->bcBitCount + 31) & ~31) >> 3);
  403.     }
  404.     else
  405.         l = (((pbm->biWidth * pbm->biBitCount + 31) & ~31) >> 3);
  406.     return l;
  407. }
  408.  
  409. /* return number of colors in color table */
  410. unsigned int
  411. dib_pal_colors(LPBITMAP2 pbm)
  412. {
  413.     if (pbm->biSize == sizeof(BITMAP1)) {
  414.     LPBITMAP1 pbm1 = (LPBITMAP1)pbm;
  415.     if (pbm1->bcBitCount != 24)
  416.         return 1<<(pbm1->bcBitCount * pbm1->bcPlanes);
  417.     }
  418.     else {
  419.     if (pbm->biBitCount != 24)
  420.         return (pbm->biClrUsed) ? (unsigned int)(pbm->biClrUsed) :
  421.         1<<(pbm->biBitCount * pbm->biPlanes);
  422.     }
  423.     return 0;
  424. }
  425.  
  426.  
  427. void
  428. scan_colors(PREBMAP *ppbmap, LPBITMAP2 pbm)
  429. {
  430.     LPRGB4 prgbquad;
  431.     LPRGB3 prgbtriple;
  432.     unsigned char rr;
  433.     unsigned char gg;
  434.     unsigned char bb;
  435.     int type_one = FALSE;
  436.     int clrtablesize;
  437.     int i;
  438.  
  439.     prgbquad   = (LPRGB4)(((BYTE GVHUGE *)pbm) + pbm->biSize);
  440.     prgbtriple = (LPRGB3)prgbquad;
  441.     if (pbm->biSize == sizeof(BITMAP1))
  442.         type_one = TRUE;
  443.     /* read in the color table */
  444.     clrtablesize = dib_pal_colors(pbm);
  445.     for (i = 0; i < clrtablesize; i++) {
  446.         if (type_one) {
  447.             bb = prgbtriple[i].rgbtBlue;
  448.             gg = prgbtriple[i].rgbtGreen;
  449.             rr = prgbtriple[i].rgbtRed;
  450.         }
  451.         else {
  452.             bb = prgbquad[i].rgbBlue;
  453.             gg = prgbquad[i].rgbGreen;
  454.             rr = prgbquad[i].rgbRed;
  455.         }
  456.         isblack[i] = (unsigned char)((rr < 0xff) || (gg < 0xff) || (bb < 0xff));
  457.     }
  458. }
  459.  
  460. /* return pointer to bitmap bits */
  461. BYTE GVHUGE *
  462. get_dib_bits(LPBITMAP2 pbm)
  463. {
  464. BYTE GVHUGE *lpDibBits;
  465.     lpDibBits = (((BYTE GVHUGE *)pbm) + pbm->biSize);
  466.     if (pbm->biSize == sizeof(BITMAP1))
  467.         lpDibBits += dib_pal_colors(pbm) * sizeof(RGB3); 
  468.     else
  469.         lpDibBits += dib_pal_colors(pbm) * sizeof(RGB4); 
  470.     return lpDibBits;
  471. }
  472. #endif /* !UNIX */
  473.  
  474. /* get line from DIB and store as 1 bit/pixel in preview */
  475. /* also works for PBM bitmap */
  476. /* preview has 0=black, 1=white */
  477. void
  478. get_dib_line(BYTE GVHUGE *line, unsigned char *preview, int width, int bitcount)
  479. {
  480. int bwidth = ((width + 7) & ~7) >> 3; /* byte width with 1 bit/pixel */
  481. unsigned char omask;
  482. int oroll;
  483. unsigned char c = 0;
  484. int j;
  485.     memset(preview,0xff,bwidth);
  486.     omask = 0x80;
  487.     oroll = 7;
  488.     if (bitcount == 1) {
  489.         if (isblack[0])
  490.         for (j = 0; j < bwidth ; j++)
  491.             preview[j] = line[j];
  492.         else
  493.         for (j = 0; j < bwidth ; j++)
  494.             preview[j] = (unsigned char)~line[j];
  495.         preview[bwidth-1] |= (unsigned char)(width & 7 ? (1<<(8-(width&7)))-1 : 0);    /* mask for edge of bitmap */
  496.     }
  497.     else {
  498.         for (j = 0; j < width; j++) {
  499.         switch (bitcount) {
  500.             case 4:
  501.                 c = line[j>>1];
  502.                 if (!(j&1))
  503.                     c >>= 4;
  504.                 c = isblack[ c & 0x0f ];
  505.                 break;
  506.             case 8:
  507.                 c = isblack[ (int)(line[j]) ];
  508.                 break;
  509.             case 24:
  510.                 c = (unsigned char)(
  511.                     (line[j*3] < 0xff) || 
  512.                     (line[j*3+1] < 0xff) || 
  513.                     (line[j*3+2] < 0xff) );
  514.                 break;
  515.         }
  516.         if (c) 
  517.             preview[j/8] &= (unsigned char)(~omask);
  518.         else
  519.             preview[j/8] |= omask;
  520.         oroll--;
  521.         omask >>= 1;
  522.         if (oroll < 0) {
  523.             omask = 0x80;
  524.             oroll = 7;
  525.         }
  526.         }
  527.     }
  528. }
  529.  
  530. #define TIFF_BYTE 1
  531. #define TIFF_ASCII 2
  532. #define TIFF_SHORT 3
  533. #define TIFF_LONG 4
  534. #define TIFF_RATIONAL 5
  535.  
  536. struct rational_s {
  537.     DWORD numerator;
  538.     DWORD denominator;
  539. };
  540.  
  541. struct ifd_entry_s {
  542.     WORD tag;
  543.     WORD type;
  544.     DWORD length;
  545.     DWORD value;
  546. };
  547.  
  548. struct tiff_head_s {
  549.     WORD order;
  550.     WORD version;
  551.     DWORD ifd_offset;
  552. };
  553.  
  554. /* write tiff file from DIB bitmap */
  555. void
  556. write_tiff(FILE *f, LPBITMAP2 pbm, BOOL tiff4)
  557. {
  558. char *now;
  559. DWORD *strip;
  560. #define IFD_MAX_ENTRY 12
  561. struct tiff_head_s tiff_head;
  562. WORD ifd_length;
  563. DWORD ifd_next;
  564. struct ifd_entry_s ifd_entry[IFD_MAX_ENTRY];
  565. struct ifd_entry_s *pifd_entry;
  566. struct rational_s rational;
  567. DWORD tiff_end, end;
  568. time_t t;
  569. int i;
  570. unsigned char *preview;
  571. BYTE GVHUGE *line;
  572. int bwidth;
  573. BOOL soft_extra = FALSE;
  574. BOOL date_extra = FALSE;
  575. PREBMAP prebmap;
  576.     
  577.     if (*(char *)pbm == 'P')
  578.         scan_pbmplus(&prebmap, pbm);
  579.     else
  580.         scan_dib(&prebmap, pbm);
  581.  
  582.     /* byte width with 1 bit/pixel, rounded up even word */
  583.     bwidth = ((prebmap.width + 15) & ~15) >> 3;
  584.  
  585.     tiff_end = sizeof(tiff_head);
  586.     if (reorder_word(1) == 1)
  587.         tiff_head.order = 0x4949;    /* Intel = little endian */
  588.     else
  589.         tiff_head.order = 0x4d4d;    /* Motorola = big endian */
  590.     tiff_head.version = 42;
  591.     tiff_head.ifd_offset = tiff_end;
  592.  
  593.     tiff_end += sizeof(ifd_length);
  594.  
  595.     if (tiff4)
  596.         ifd_length = 10;
  597.     else
  598.         ifd_length = 12;
  599.  
  600.     tiff_end += ifd_length * sizeof(struct ifd_entry_s) + sizeof(ifd_next);
  601.     ifd_next = 0;
  602.     pifd_entry = &ifd_entry[0];
  603.     if (tiff4) {
  604.         pifd_entry->tag = 0xff;    /* SubfileType */
  605.         pifd_entry->type = TIFF_SHORT;
  606.     }
  607.     else {
  608.         pifd_entry->tag = 0xfe;    /* NewSubfileType */
  609.         pifd_entry->type = TIFF_LONG;
  610.     }
  611.     pifd_entry->length = 1;
  612.     pifd_entry->value = 0;
  613.  
  614.     pifd_entry = &ifd_entry[1];
  615.     pifd_entry->tag = 0x100;    /* ImageWidth */
  616.     if (tiff4)
  617.         pifd_entry->type = TIFF_SHORT;
  618.     else
  619.         pifd_entry->type = TIFF_LONG;
  620.     pifd_entry->length = 1;
  621.     pifd_entry->value = prebmap.width;
  622.  
  623.     pifd_entry = &ifd_entry[2];
  624.     pifd_entry->tag = 0x101;    /* ImageLength */
  625.     if (tiff4)
  626.         pifd_entry->type = TIFF_SHORT;
  627.     else
  628.         pifd_entry->type = TIFF_LONG;
  629.     pifd_entry->length = 1;
  630.     pifd_entry->value = prebmap.height;
  631.  
  632.     pifd_entry = &ifd_entry[3];
  633.     pifd_entry->tag = 0x103;    /* Compression */
  634.     pifd_entry->type = TIFF_SHORT;
  635.     pifd_entry->length = 1;
  636.     pifd_entry->value = 1;        /* no compression */
  637.  
  638.     pifd_entry = &ifd_entry[4];
  639.     pifd_entry->tag = 0x106;    /* PhotometricInterpretation */
  640.     pifd_entry->type = TIFF_SHORT;
  641.     pifd_entry->length = 1;
  642.     pifd_entry->value = 1;        /* black is zero */
  643.  
  644.     pifd_entry = &ifd_entry[5];
  645.     pifd_entry->tag = 0x111;    /* StripOffsets */
  646.     pifd_entry->type = TIFF_LONG;
  647.     pifd_entry->length = prebmap.height;
  648.     pifd_entry->value = tiff_end;
  649.     tiff_end += (pifd_entry->length * sizeof(DWORD));
  650.  
  651.     pifd_entry = &ifd_entry[6];
  652.     pifd_entry->tag = 0x116;    /* RowsPerStrip */
  653.     pifd_entry->type = TIFF_LONG;
  654.     pifd_entry->length = 1;
  655.     pifd_entry->value = 1;
  656.  
  657.     pifd_entry = &ifd_entry[7];
  658.     pifd_entry->tag = 0x117;    /* StripByteCounts */
  659.     pifd_entry->type = TIFF_LONG;
  660.     pifd_entry->length = prebmap.height;
  661.     pifd_entry->value = tiff_end;
  662.     tiff_end += (pifd_entry->length * sizeof(DWORD));
  663.  
  664.     pifd_entry = &ifd_entry[8];
  665.     pifd_entry->tag = 0x11a;    /* XResolution */
  666.     pifd_entry->type = TIFF_RATIONAL;
  667.     pifd_entry->length = 1;
  668.     pifd_entry->value = tiff_end;
  669.     tiff_end += sizeof(struct rational_s);
  670.  
  671.     pifd_entry = &ifd_entry[9];
  672.     pifd_entry->tag = 0x11b;    /* YResolution */
  673.     pifd_entry->type = TIFF_RATIONAL;
  674.     pifd_entry->length = 1;
  675.     pifd_entry->value = tiff_end;
  676.     tiff_end += sizeof(struct rational_s);
  677.  
  678.     if (!tiff4) {
  679.         pifd_entry = &ifd_entry[10];
  680.         pifd_entry->tag = 0x131;    /* Software */
  681.         pifd_entry->type = TIFF_ASCII;
  682.         pifd_entry->length = strlen(szAppName) + 1;
  683.         pifd_entry->value = tiff_end;
  684.         tiff_end += pifd_entry->length;
  685.         if (tiff_end & 1) { /* pad to word boundary */
  686.             soft_extra = TRUE;
  687.             tiff_end++;
  688.         }
  689.  
  690.         pifd_entry = &ifd_entry[11];
  691.         pifd_entry->tag = 0x132;    /* DateTime */
  692.         pifd_entry->type = TIFF_ASCII;
  693.         t = time(NULL);
  694.         now = ctime(&t);
  695.         now[strlen(now)-1] = '\0';    /* remove trailing \n */
  696.         pifd_entry->length = strlen(now)+1;
  697.         pifd_entry->value = tiff_end;
  698.         tiff_end += pifd_entry->length;
  699.         if (tiff_end & 1) { /* pad to word boundary */
  700.             date_extra = TRUE;
  701.             tiff_end++;
  702.         }
  703.     }
  704.  
  705.     fwrite(&tiff_head, sizeof(tiff_head), 1, f);
  706.     fwrite(&ifd_length, sizeof(ifd_length), 1, f);
  707.     fwrite(ifd_entry, ifd_length * sizeof(struct ifd_entry_s), 1, f);
  708.     fwrite(&ifd_next, sizeof(ifd_next), 1, f);
  709.     strip = (DWORD *)malloc(prebmap.height * sizeof(DWORD));
  710.     end = tiff_end;
  711.     for (i=0; i<prebmap.height; i++) {
  712.         strip[i] = end;        /* strip offsets */
  713.         end += bwidth;
  714.     }
  715.     fwrite(strip, 1, prebmap.height * sizeof(DWORD), f);
  716.     for (i=0; i<prebmap.height; i++)
  717.         strip[i] = bwidth;    /* strip byte counts */
  718.     fwrite(strip, 1, prebmap.height * sizeof(DWORD), f);
  719.     free((void *)strip);
  720.     rational.numerator = (int)option.xdpi;
  721.     rational.denominator = 1;
  722.     fwrite(&rational, sizeof(rational), 1, f);
  723.     rational.numerator = (int)option.ydpi;
  724.     rational.denominator = 1;
  725.     fwrite(&rational, sizeof(rational), 1, f);
  726.     if (!tiff4) {
  727.         fwrite(szAppName, 1, strlen(szAppName)+1, f);
  728.         if (soft_extra)
  729.             fputc('\0',f);
  730.         fwrite(now, 1, strlen(now)+1, f);
  731.         if (date_extra)
  732.             fputc('\0',f);
  733.     }
  734.  
  735.     preview = (unsigned char *) malloc(bwidth);
  736.     memset(preview,0xff,bwidth);
  737.  
  738.     if (prebmap.topleft)
  739.         line = (BYTE GVHUGE *)prebmap.bits;
  740.     else
  741.         line = (BYTE GVHUGE *)prebmap.bits + ((long)prebmap.bytewidth * (prebmap.height-1));
  742.         /* process each line of bitmap */
  743.     for (i = 0; i < prebmap.height; i++) {
  744.         get_dib_line(line, preview, prebmap.width, prebmap.depth);
  745.         fwrite(preview, 1, bwidth, f);
  746.         if (prebmap.topleft)
  747.         line += prebmap.bytewidth;
  748.         else
  749.         line -= prebmap.bytewidth;
  750.     }
  751.     free(preview);
  752. }
  753.  
  754.  
  755. /* make a PC EPS file with a TIFF Preview */
  756. /* from a PS file and a bitmap */
  757. void
  758. make_eps_tiff(int type)
  759. {
  760. char epsname[MAXSTR];
  761. LPBITMAP2 pbm;
  762. char *buffer;
  763. unsigned int count;
  764. FILE *epsfile;
  765. FILE *tiff_file;
  766. char tiffname[MAXSTR];
  767. #ifdef __EMX__
  768. #pragma pack(1)
  769. #endif
  770. struct eps_header_s eps_header;
  771. #ifdef __EMX__
  772. #pragma pack()
  773. #endif
  774.  
  775.     
  776.     if ( (pbm = get_bitmap()) == (LPBITMAP2)NULL) {
  777.         play_sound(SOUND_ERROR);
  778.         return;
  779.     }
  780.  
  781.     if ( (tiff_file = gp_open_scratch_file(szScratch, tiffname, "wb")) == (FILE *)NULL) {
  782.         play_sound(SOUND_ERROR);
  783.         release_bitmap();
  784.         return;
  785.     }
  786.     write_tiff(tiff_file, pbm, (type == IDM_MAKEEPST4));
  787.     fclose(tiff_file);
  788.     release_bitmap();
  789.  
  790. #ifdef EPSTOOL
  791.     strcpy(epsname, oname);
  792.     if (*epsname!='\0')
  793.         epsfile = fopen(epsname,"wb");
  794.     else
  795.         epsfile = stdout;
  796. #else
  797.     /* create EPS file */
  798.     epsname[0] = '\0';
  799.     if (!get_filename(epsname, TRUE, FILTER_EPS, 0, IDS_TOPICEDIT)) {
  800.         unlink(tiffname);
  801.         return;
  802.     }
  803.     epsfile = fopen(epsname,"wb");
  804. #endif
  805.     if (epsfile == (FILE *)NULL) {
  806.         play_sound(SOUND_ERROR);
  807.         release_bitmap();
  808.         return;
  809.     }
  810.  
  811.     /* write DOS EPS binary header */
  812.     eps_header.id[0] = 0xc5;
  813.     eps_header.id[1] = 0xd0;
  814.     eps_header.id[2] = 0xd3;
  815.     eps_header.id[3] = 0xc6;
  816.     eps_header.ps_begin = sizeof(eps_header);
  817.     fseek(psfile.file, 0, SEEK_END);
  818.     eps_header.ps_length = ftell(psfile.file);
  819.     eps_header.mf_begin = 0;
  820.     eps_header.mf_length = 0;
  821.     eps_header.tiff_begin = eps_header.ps_begin + eps_header.ps_length;
  822.     tiff_file = fopen(tiffname,"rb");
  823.     fseek(tiff_file, 0, SEEK_END);
  824.     eps_header.tiff_length = ftell(tiff_file);
  825.     eps_header.checksum = -1;
  826.     /* reverse byte order if big endian machine */
  827.     eps_header.ps_begin = reorder_dword(eps_header.ps_begin);
  828.     eps_header.ps_length = reorder_dword(eps_header.ps_length);
  829.     eps_header.tiff_begin = reorder_dword(eps_header.tiff_begin);
  830.     eps_header.tiff_length = reorder_dword(eps_header.tiff_length);
  831.     fwrite(&eps_header, sizeof(eps_header), 1, epsfile);
  832.     rewind(psfile.file);
  833.     dsc_copy(psfile.file, epsfile, doc->begincomments, doc->endtrailer, NULL);
  834.     
  835.     /* copy tiff file */
  836.     rewind(tiff_file);
  837.     buffer = malloc(COPY_BUF_SIZE);
  838.     if (buffer == (char *)NULL) {
  839.         play_sound(SOUND_ERROR);
  840.         fclose(epsfile);
  841.         unlink(epsname);
  842.         fclose(tiff_file);
  843.         unlink(tiffname);
  844.         return;
  845.     }
  846.         while ( (count = fread(buffer, 1, COPY_BUF_SIZE, tiff_file)) != 0 )
  847.         fwrite(buffer, 1, count, epsfile);
  848.     free(buffer);
  849.     fclose(tiff_file);
  850.     unlink(tiffname);
  851.     if (*epsname!='\0')
  852.        fclose(epsfile);
  853. }
  854.  
  855. static char hex[16] = "0123456789ABCDEF";
  856.  
  857. /* write interchange preview to file f */
  858. void
  859. write_interchange(FILE *f, LPBITMAP2 pbm, BOOL calc_bbox)
  860. {
  861.     int i, j;
  862.     unsigned char *preview;
  863.     BYTE GVHUGE *line;
  864.     int preview_width, bwidth;
  865.     int lines_per_scan;
  866.     PREBMAP prebmap;
  867.     PSBBOX devbbox;    /* in pixel units */
  868.     
  869.     if (*(char *)pbm == 'P')
  870.         scan_pbmplus(&prebmap, pbm);
  871.     else
  872.         scan_dib(&prebmap, pbm);
  873.     
  874.     if (calc_bbox) {
  875.         scan_bbox(&prebmap, &devbbox);
  876.         if (devbbox.valid) {
  877.             /* copy to global bbox as if obtained by PS to EPS */
  878.             bbox.llx = devbbox.llx * 72.0 / option.xdpi;
  879.             bbox.lly = devbbox.lly * 72.0 / option.ydpi;
  880.             bbox.urx = devbbox.urx * 72.0 / option.xdpi;
  881.             bbox.ury = devbbox.ury * 72.0 / option.ydpi;
  882.             bbox.valid = TRUE;
  883.         }
  884.         copy_bbox_header(f); /* adjust %%BoundingBox: comment */
  885.     }
  886.     else {
  887.         devbbox.urx = prebmap.width;
  888.         devbbox.ury = prebmap.height;
  889.         devbbox.llx = devbbox.lly = 0;
  890.         dsc_copy(psfile.file, f, doc->begincomments, doc->endcomments, NULL);
  891.     }
  892.  
  893.     bwidth = (((devbbox.urx-devbbox.llx) + 7) & ~7) >> 3; /* byte width with 1 bit/pixel */
  894.     preview_width = ((prebmap.width + 7) & ~7) >> 3; /* byte width with 1 bit/pixel */
  895.  
  896.     preview = (unsigned char *) malloc(preview_width);
  897.  
  898.     lines_per_scan = ((bwidth-1) / 32) + 1;
  899.     fprintf(f,"%%%%BeginPreview: %u %u 1 %u",(devbbox.urx-devbbox.llx), (devbbox.ury-devbbox.lly), 
  900.         (devbbox.ury-devbbox.lly)*lines_per_scan);
  901.     fputs(EOLSTR, f);
  902.  
  903.     if (prebmap.topleft)
  904.         line = (BYTE GVHUGE *)prebmap.bits + ((long)prebmap.bytewidth * (prebmap.height - devbbox.ury));
  905.     else
  906.         line = (BYTE GVHUGE *)prebmap.bits + ((long)prebmap.bytewidth * (devbbox.ury-1));
  907.     /* process each line of bitmap */
  908.     for (i = 0; i < (devbbox.ury-devbbox.lly); i++) {
  909.         get_dib_line(line, preview, prebmap.width, prebmap.depth);
  910.         if (devbbox.llx)
  911.             shift_preview(preview, preview_width, devbbox.llx);
  912.         fputs("% ",f);
  913.         for (j=0; j<bwidth; j++) {
  914.             if (j && ((j & 31) == 0)) {
  915.             fputs(EOLSTR, f);
  916.                 fputs("% ",f);
  917.             }
  918.             fputc(hex[15-((preview[j]>>4)&15)],f);
  919.             fputc(hex[15-((preview[j])&15)],f);
  920.         }
  921.         fputs(EOLSTR, f);
  922.         if (prebmap.topleft)
  923.             line += prebmap.bytewidth;
  924.         else 
  925.             line -= prebmap.bytewidth;
  926.     }
  927.  
  928.     fputs("%%EndPreview",f);
  929.     fputs(EOLSTR, f);
  930.     free(preview);
  931.     dsc_copy(psfile.file, f, doc->endpreview, doc->endtrailer, NULL);
  932. }
  933.  
  934. /* make an EPSI file with an Interchange Preview */
  935. /* from a PS file and a bitmap */
  936. void
  937. make_eps_interchange(BOOL calc_bbox)
  938. {
  939. char epiname[MAXSTR];
  940. FILE *epifile;
  941. LPBITMAP2 pbm;
  942.  
  943.     if ( (pbm = get_bitmap()) == (LPBITMAP2)NULL) {
  944.         play_sound(SOUND_ERROR);
  945.         return;
  946.     }
  947.  
  948. #ifdef EPSTOOL
  949.     strcpy(epiname, oname);
  950.     if (*epiname!='\0')
  951.         epifile = fopen(epiname,"wb");
  952.     else
  953.         epifile = stdout;
  954. #else
  955.     /* create EPI file */
  956.     epiname[0] = '\0';
  957.     if (!get_filename(epiname, TRUE, FILTER_EPI, 0, IDS_TOPICEDIT)) {
  958.         play_sound(SOUND_ERROR);
  959.         release_bitmap();
  960.         return;
  961.     }
  962.     epifile = fopen(epiname,"wb");
  963. #endif
  964.  
  965.     if (epifile == (FILE *)NULL) {
  966.         play_sound(SOUND_ERROR);
  967.         release_bitmap();
  968.         return;
  969.     }
  970.  
  971.     rewind(psfile.file);
  972.     write_interchange(epifile, pbm, calc_bbox);
  973.     if (*epiname!='\0')
  974.         fclose(epifile);
  975.     release_bitmap();
  976. }
  977.  
  978.  
  979. /* scan bitmap and return bbox measured in pixels */
  980. void
  981. scan_bbox(PREBMAP *pprebmap, PSBBOX *devbbox)
  982. {
  983.     unsigned char *preview;
  984.     BYTE GVHUGE *line;
  985.     int bwidth = ((pprebmap->width + 7) & ~7) >> 3; /* byte width with 1 bit/pixel */
  986.     int i, j, k, l;
  987.     int x;
  988.     BYTE ch;
  989.     BYTE GVHUGE *chline;
  990.     unsigned char omask;
  991.  
  992.     devbbox->llx = pprebmap->width;
  993.     devbbox->lly = pprebmap->height;
  994.     devbbox->urx = devbbox->ury = 0;
  995.     devbbox->valid = FALSE;
  996.  
  997.     preview = (unsigned char *) malloc(bwidth);
  998.     memset(preview,0xff,bwidth);
  999.  
  1000.     if (pprebmap->topleft)
  1001.         line = (BYTE GVHUGE *)pprebmap->bits + ((long)pprebmap->bytewidth * (pprebmap->height-1));
  1002.     else
  1003.         line = (BYTE GVHUGE *)pprebmap->bits;
  1004.         /* process each line of bitmap */
  1005.     for (i = 0; i < pprebmap->height; i++) {
  1006.         /* get 1bit/pixel line, 0=black, 1=white */
  1007.         get_dib_line(line, preview, pprebmap->width, pprebmap->depth);
  1008.         chline = preview;
  1009.         ch = 0;
  1010.         for (j=0; j<bwidth; j++)
  1011.             ch |= ~(*chline++);    /* check for black pixels */
  1012.         if (ch) {
  1013.         /* adjust y coordinates of bounding box */
  1014.         if (i < devbbox->lly)
  1015.             devbbox->lly = i;
  1016.         if (i+1 > devbbox->ury)
  1017.             devbbox->ury = i+1;
  1018.         /* scan for x coordinates of black pixels */
  1019.             chline = preview;
  1020.         for (k=0; k<bwidth; k++) {
  1021.             if (~(*chline)) { /* a pixel is black */
  1022.             omask = 0x80;
  1023.             for (l=0; l<8; l++) {
  1024.                 if ( ~*chline & omask ) {
  1025.                     x = k*8 + l;
  1026.                     if (x < devbbox->llx)
  1027.                         devbbox->llx = x;
  1028.                     if (x+1 > devbbox->urx)
  1029.                         devbbox->urx = x+1;
  1030.                 }
  1031.                     omask >>= 1;
  1032.             }
  1033.             }
  1034.             chline++;
  1035.         }
  1036.         }
  1037.         if (pprebmap->topleft)
  1038.         line -= pprebmap->bytewidth;
  1039.         else
  1040.         line += pprebmap->bytewidth;
  1041.     }
  1042.     free(preview);
  1043.     if ( (devbbox->lly < devbbox->ury) && (devbbox->llx < devbbox->urx) )
  1044.         devbbox->valid = TRUE;
  1045.     
  1046. #ifdef EPSTOOL
  1047.     {   char buf[256];
  1048.         sprintf(buf, "bbox=%d %d %d %d\n", devbbox->llx, devbbox->lly, devbbox->urx, devbbox->ury);
  1049.         pserror(buf);
  1050.     }
  1051. #endif
  1052. }
  1053.  
  1054. /* shift preview by offset bits to the left */
  1055. /* width is in bytes */
  1056. /* fill exposed bits with 1's */
  1057. void
  1058. shift_preview(unsigned char *preview, int bwidth, int offset)
  1059. {
  1060. int bitoffset;
  1061. int byteoffset;
  1062. int newwidth;
  1063. int shifter;
  1064. int i;
  1065.     if (offset == 0)
  1066.         return;
  1067.     byteoffset = offset / 8;
  1068.     newwidth = bwidth - byteoffset;
  1069.     /* first remove byte offset */
  1070.     memmove(preview, preview+byteoffset, newwidth);
  1071.     memset(preview+newwidth, 0xff, bwidth-newwidth);
  1072.     /* next remove bit offset */
  1073.     bitoffset = offset - byteoffset*8;
  1074.     if (bitoffset==0)
  1075.         return;
  1076.     bitoffset = 8 - bitoffset;
  1077.     for (i=0; i<newwidth; i++) {
  1078.        shifter = preview[i] << 8;
  1079.        if (i==newwidth-1)
  1080.            shifter += 0xff;    /* can't access preview[bwidth] */
  1081.        else
  1082.            shifter += preview[i+1];  
  1083.        preview[i] = shifter>>bitoffset;
  1084.     }
  1085. }
  1086.  
  1087. /* Copy the header to file f */
  1088. /* change bbox line if present, or add bbox line */
  1089. void
  1090. copy_bbox_header(FILE *f)
  1091. {
  1092.     char text[PSLINELENGTH];
  1093.     char *comment;
  1094.     BOOL bbox_written = FALSE;
  1095.     long position;
  1096.  
  1097.     fseek(psfile.file, doc->begincomments, SEEK_SET);
  1098.     if (doc->bbox.valid) {
  1099.       position = ftell(psfile.file);
  1100.       while ( (comment = dsc_copy(psfile.file, f, position,
  1101.                doc->endcomments, "%%BoundingBox:")) != (char *)NULL ) {
  1102.     position = ftell(psfile.file);
  1103.     if (bbox_written) {
  1104.         free(comment);
  1105.         continue;
  1106.     }
  1107.     fprintf(f, "%%%%BoundingBox: %d %d %d %d\r\n",
  1108.         bbox.llx, bbox.lly, bbox.urx, bbox.ury);
  1109.     bbox_written = TRUE;
  1110.     free(comment);
  1111.       }
  1112.     }
  1113.     else {
  1114.       fgets(text, PSLINELENGTH, psfile.file);
  1115.       fputs(text,f);
  1116.       fprintf(f, "%%%%BoundingBox: %d %d %d %d\r\n",
  1117.         bbox.llx, bbox.lly, bbox.urx, bbox.ury);
  1118.       position = ftell(psfile.file);
  1119.       comment = dsc_copy(psfile.file, f, position, doc->endcomments, NULL);
  1120.     }
  1121. }
  1122.  
  1123.